﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Reflection;
using AnaxibiaStudios.Smug.Advanced;
using AnaxibiaStudios.Smug.Internal;

namespace SmugTest
{
  [TestClass]
  public class MethodOverrideMetaTest
  {
    public interface MOS_I_01 { void IA_01(); void IB_01(); void IC_01(); void ID_01(); }
    public interface MOS_I_02 { void IA_02(); void IB_02(); void IC_02(); void ID_02(); }
    public interface MOS_I_03 { void IA_03(); void IB_03(); void IC_03(); void ID_03(); }
    public interface MOS_I_04 { void IA_04(); void IB_04(); void IC_04(); void ID_04(); }

    public class MOS_C_1 : MOS_I_01
    {
      public void IA_01() { }
      public virtual void IB_01() { }
      public /*abstract*/ void IC_01() { }
      void MOS_I_01.ID_01() { }
    }

    public abstract class MOS_C_2 : MOS_I_01
    {
      public void IA_01() { }
      public virtual void IB_01() { }
      public abstract void IC_01();
      void MOS_I_01.ID_01() { }
    }

    public class MOS_Setup_3 : MOS_I_01, MOS_I_02, MOS_I_03
    {
      public void IA_01() { }
      public void IB_01() { }
      public void IC_01() { }
      public void ID_01() { }

      public virtual void IA_02() { }
      public virtual void IB_02() { }
      public virtual void IC_02() { }
      public virtual void ID_02() { }

      // no abstracts as this class is not abstract

      void MOS_I_03.IA_03() { }
      void MOS_I_03.IB_03() { }
      void MOS_I_03.IC_03() { }
      void MOS_I_03.ID_03() { }
    }

    public class MOS_C_3 : MOS_Setup_3, MOS_I_01, MOS_I_02, MOS_I_03
    {
      public void IA_01() { }
      public virtual void IB_01() { }
      public new void IC_01() { }
      void MOS_I_01.ID_01() { }

      public void IA_02() { }
      public virtual void IB_02() { }
      public new void IC_02() { }
      void MOS_I_02.ID_02() { }

      public void IA_03() { }
      public virtual void IB_03() { }
      public new void IC_03() { }
      void MOS_I_03.ID_03() { }
    }

    public abstract class MOS_C_4 : MOS_Setup_3, MOS_I_01, MOS_I_02, MOS_I_03
    {
      public void IA_01() { }
      public virtual void IB_01() { }
      public abstract void IC_01();
      void MOS_I_01.ID_01() { }

      public void IA_02() { }
      public virtual void IB_02() { }
      public abstract void IC_02();
      void MOS_I_02.ID_02() { }

      public void IA_03() { }
      public virtual void IB_03() { }
      public abstract void IC_03();
      void MOS_I_03.ID_03() { }
    }

    public abstract class MOS_Setup_5 : MOS_I_01
    {
      void MOS_I_01.IA_01() { }
      void MOS_I_01.IB_01() { }
      void MOS_I_01.IC_01() { }
      void MOS_I_01.ID_01() { }
    }

    public abstract class MOS_C_5 : MOS_Setup_5, MOS_I_01
    {
      void MOS_I_01.IA_01() { }
      void MOS_I_01.IB_01() { }
      void MOS_I_01.IC_01() { }
      void MOS_I_01.ID_01() { }

      public void IA_01() { }
      public virtual void IB_01() { }
      public abstract void IC_01();
    }

    public abstract class MOS_Setup_6 : MOS_I_01, MOS_I_02, MOS_I_03, MOS_I_04
    {
      public void IA_01() { }
      public void IB_01() { }
      public void IC_01() { }
      public void ID_01() { }

      public virtual void IA_02() { }
      public virtual void IB_02() { }
      public virtual void IC_02() { }
      public virtual void ID_02() { }

      public abstract void IA_03();
      public abstract void IB_03();
      public abstract void IC_03();
      public abstract void ID_03();

      void MOS_I_04.IA_04() { }
      void MOS_I_04.IB_04() { }
      void MOS_I_04.IC_04() { }
      void MOS_I_04.ID_04() { }
    }

    public class MOS_C_6 : MOS_Setup_6, MOS_I_01, MOS_I_02, MOS_I_03, MOS_I_04
    {
      public new void IA_01() { }
      public virtual void IB_01() { }
      public new void IC_01() { }
      void MOS_I_01.ID_01() { }

      public override void IA_02() { }
      public override void IB_02() { }
      public override void IC_02() { }
      void MOS_I_02.ID_02() { }

      public override void IA_03() { }
      public override void IB_03() { }
      public override void IC_03() { }
      public override void ID_03() { }

      public void IA_04() { }
      public virtual void IB_04() { }
      public void IC_04() { }
      void MOS_I_04.ID_04() { }
    }

    public interface MOS_I_05
    {
      void IA_05();
      void ID_05();
      void IF_05();
      void IG_05();

      void IH_05();

      int IJ_05 { get; set; }
      int IK_05 { get; }
      int IL_05 { set; }

      int IM_05 { get; set; }
      int IN_05 { get; }
      int IO_05 { set; }

      event Action IP_05;
      event Action IQ_05;
    }

    public abstract class MOS_C_7 : MOS_I_05
    {
      public void IA_05() { }
      protected void B() { }
      private void C() { }

      public virtual void ID_05() { }
      protected virtual void E() { }
      void MOS_I_05.IF_05() { }
      protected virtual void IF_05() { }

      public abstract void IG_05();

      void MOS_I_05.IH_05() { }
      protected abstract void IH_05();

      protected abstract void I();

      int MOS_I_05.IJ_05 { get; set; }
      protected virtual int IJ_05 { get; set; }
      int MOS_I_05.IK_05 { get { throw new NotImplementedException(); } }
      protected virtual int IK_05 { get { throw new NotImplementedException(); } }
      int MOS_I_05.IL_05 { set { throw new NotImplementedException(); } }
      protected virtual int IL_05 { set { throw new NotImplementedException(); } }

      public int IM_05 { get; set; }
      public int IN_05 { get { throw new NotImplementedException(); } }
      public int IO_05 { set { throw new NotImplementedException(); } }

      public event Action IP_05;
      event Action MOS_I_05.IQ_05 { add { throw new NotImplementedException(); } remove { throw new NotImplementedException(); } }
      protected abstract event Action IQ_05;
      public virtual event Action R;
      protected abstract event Action S;
      private event Action T;
    }

    [TestMethod]
    public void MOS_0_Test()
    {
      MosHelper<MOS_I_01>(MethodOverrideState.Virtual, "IA_01");
      MosHelper<MOS_I_01>(MethodOverrideState.Virtual, "IB_01");
      MosHelper<MOS_I_01>(MethodOverrideState.Virtual, "IC_01");
      MosHelper<MOS_I_01>(MethodOverrideState.Virtual, "ID_01");
    }

    [TestMethod]
    public void MOS_1_Test()
    {
      MosHelper<MOS_C_1>(MethodOverrideState.Sealed, "IA_01");
      MosHelper<MOS_C_1>(MethodOverrideState.Virtual, "IB_01");
      MosHelper<MOS_C_1>(MethodOverrideState.Sealed, "IC_01");
      MosHelper<MOS_C_1>(MethodOverrideState.Explicit, "ID_01");
    }

    [TestMethod]
    public void MOS_2_Test()
    {
      MosHelper<MOS_C_2>(MethodOverrideState.Sealed, "IA_01");
      MosHelper<MOS_C_2>(MethodOverrideState.Virtual, "IB_01");
      MosHelper<MOS_C_2>(MethodOverrideState.Abstract, "IC_01");
      MosHelper<MOS_C_2>(MethodOverrideState.Explicit, "ID_01");
    }

    [TestMethod]
    public void MOS_3_Test()
    {
      MosHelper<MOS_C_3>(MethodOverrideState.Sealed, "IA_01");
      MosHelper<MOS_C_3>(MethodOverrideState.Virtual, "IB_01");
      MosHelper<MOS_C_3>(MethodOverrideState.Sealed, "IC_01");
      MosHelper<MOS_C_3>(MethodOverrideState.Explicit, "ID_01");

      MosHelper<MOS_C_3>(MethodOverrideState.Sealed, "IA_02");
      MosHelper<MOS_C_3>(MethodOverrideState.Virtual, "IB_02");
      MosHelper<MOS_C_3>(MethodOverrideState.Sealed, "IC_02");
      MosHelper<MOS_C_3>(MethodOverrideState.Explicit, "ID_02");

      MosHelper<MOS_C_3>(MethodOverrideState.Sealed, "IA_03");
      MosHelper<MOS_C_3>(MethodOverrideState.Virtual, "IB_03");
      MosHelper<MOS_C_3>(MethodOverrideState.Sealed, "IC_03");
      MosHelper<MOS_C_3>(MethodOverrideState.Explicit, "ID_03");
    }

    [TestMethod]
    public void MOS_4_Test()
    {
      MosHelper<MOS_C_4>(MethodOverrideState.Sealed, "IA_01");
      MosHelper<MOS_C_4>(MethodOverrideState.Virtual, "IB_01");
      MosHelper<MOS_C_4>(MethodOverrideState.Abstract, "IC_01");
      MosHelper<MOS_C_4>(MethodOverrideState.Explicit, "ID_01");

      MosHelper<MOS_C_4>(MethodOverrideState.Sealed, "IA_02");
      MosHelper<MOS_C_4>(MethodOverrideState.Virtual, "IB_02");
      MosHelper<MOS_C_4>(MethodOverrideState.Abstract, "IC_02");
      MosHelper<MOS_C_4>(MethodOverrideState.Explicit, "ID_02");

      MosHelper<MOS_C_4>(MethodOverrideState.Sealed, "IA_03");
      MosHelper<MOS_C_4>(MethodOverrideState.Virtual, "IB_03");
      MosHelper<MOS_C_4>(MethodOverrideState.Abstract, "IC_03");
      MosHelper<MOS_C_4>(MethodOverrideState.Explicit, "ID_03");
    }

    [TestMethod]
    public void MOS_5_Test()
    {
      MosHelper<MOS_C_5>(MethodOverrideState.Explicit, "IA_01", true);
      MosHelper<MOS_C_5>(MethodOverrideState.Explicit, "IB_01", true);
      MosHelper<MOS_C_5>(MethodOverrideState.Explicit, "IC_01", true);
      MosHelper<MOS_C_5>(MethodOverrideState.Explicit, "ID_01");

      MosHelper<MOS_C_5>(MethodOverrideState.Sealed, "IA_01", false);
      MosHelper<MOS_C_5>(MethodOverrideState.Virtual, "IB_01", false);
      MosHelper<MOS_C_5>(MethodOverrideState.Abstract, "IC_01", false);
    }

    [TestMethod]
    public void MOS_6_Test()
    {
      MosHelper<MOS_C_6>(MethodOverrideState.Sealed, "IA_01");
      MosHelper<MOS_C_6>(MethodOverrideState.Virtual, "IB_01");
      MosHelper<MOS_C_6>(MethodOverrideState.Sealed, "IC_01");
      MosHelper<MOS_C_6>(MethodOverrideState.Explicit, "ID_01");

      MosHelper<MOS_C_6>(MethodOverrideState.Virtual, "IA_02");
      MosHelper<MOS_C_6>(MethodOverrideState.Virtual, "IB_02");
      MosHelper<MOS_C_6>(MethodOverrideState.Virtual, "IC_02");
      MosHelper<MOS_C_6>(MethodOverrideState.Explicit, "ID_02");

      MosHelper<MOS_C_6>(MethodOverrideState.Virtual, "IA_03");
      MosHelper<MOS_C_6>(MethodOverrideState.Virtual, "IB_03");
      MosHelper<MOS_C_6>(MethodOverrideState.Virtual, "IC_03");
      MosHelper<MOS_C_6>(MethodOverrideState.Virtual, "ID_03");

      MosHelper<MOS_C_6>(MethodOverrideState.Sealed, "IA_04");
      MosHelper<MOS_C_6>(MethodOverrideState.Virtual, "IB_04");
      MosHelper<MOS_C_6>(MethodOverrideState.Sealed, "IC_04");
      MosHelper<MOS_C_6>(MethodOverrideState.Explicit, "ID_04");
    }

    [TestMethod]
    public void MOS_7_Test()
    {
      MosHelper<MOS_C_7>(MethodOverrideState.Sealed, "IA_05");
      MosHelper<MOS_C_7>(MethodOverrideState.Sealed, "B");
      MosHelper<MOS_C_7>(MethodOverrideState.Sealed, "C");
      MosHelper<MOS_C_7>(MethodOverrideState.Virtual, "ID_05");
      MosHelper<MOS_C_7>(MethodOverrideState.Virtual, "E");
      MosHelper<MOS_C_7>(MethodOverrideState.Explicit, "IF_05", true);
      MosHelper<MOS_C_7>(MethodOverrideState.Virtual, "IF_05", false);
      MosHelper<MOS_C_7>(MethodOverrideState.Abstract, "IG_05");
      MosHelper<MOS_C_7>(MethodOverrideState.Explicit, "IH_05", true);
      MosHelper<MOS_C_7>(MethodOverrideState.Abstract, "IH_05", false);
      MosHelper<MOS_C_7>(MethodOverrideState.Abstract, "I");

      MosHelper<MOS_C_7>(MethodOverrideState.Explicit, "IJ_05", true);
      MosHelper<MOS_C_7>(MethodOverrideState.Virtual, "IJ_05", false);
      MosHelper<MOS_C_7>(MethodOverrideState.Explicit, "IK_05", true);
      MosHelper<MOS_C_7>(MethodOverrideState.Virtual, "IK_05", false);
      MosHelper<MOS_C_7>(MethodOverrideState.Explicit, "IL_05", true);
      MosHelper<MOS_C_7>(MethodOverrideState.Virtual, "IL_05", false);
      MosHelper<MOS_C_7>(MethodOverrideState.Sealed, "IM_05");
      MosHelper<MOS_C_7>(MethodOverrideState.Sealed, "IN_05");
      MosHelper<MOS_C_7>(MethodOverrideState.Sealed, "IO_05");

      MosHelper<MOS_C_7>(MethodOverrideState.Sealed, "IP_05");
      MosHelper<MOS_C_7>(MethodOverrideState.Explicit, "IQ_05", true);
      MosHelper<MOS_C_7>(MethodOverrideState.Abstract, "IQ_05", false);
      MosHelper<MOS_C_7>(MethodOverrideState.Virtual, "R");
      MosHelper<MOS_C_7>(MethodOverrideState.Abstract, "S");
      MosHelper<MOS_C_7>(MethodOverrideState.Sealed, "T");
    }

    private void MosHelper<TargetType>(MethodOverrideState expected, string name, bool? useExplicit = null)
    {
      var builder = new SourceBuilder(typeof(TargetType));
      string typeMsg = string.Format("{0} - {1} [{2}]", builder.TargetType.Name, name, useExplicit.HasValue ? (useExplicit.Value ? "explicit" : "implicit") : "default");
      var collection = builder.MemberCollection;
      var member = collection[name, useExplicit];

      Assert.IsNotNull(member, string.Format("Failed to select member {0}", typeMsg));
      Assert.AreEqual(expected, GetStateValue(member), typeMsg);
    }

    public static MethodOverrideState GetStateValue(MemberInfoEx target)
    {
      var prop = typeof(MemberInfoEx).GetProperty("OverrideState", Constants.Flags);
      return (MethodOverrideState)prop.GetValue(target, new object[] { });
    }
  }
}
